#include "../include/lua_extend.h"
#include "../include/common.h"
#include "../include/glog/logging.h"
#include "../include/libuv/uv.h"
#include "../include/netallocator/NedAllocatorImpl.h"
#include "../include/molenet.h"
#include "../include/debuger/ldb.h"

lua_State* g_lua_state = NULL;

std::map< uv_timer_t*, uint32 > m_timerinkedRefs;

ldb_t *ldb;

static int c_break(lua_State *state) {
	ldb_break(state);
	return 0;
}

void reload(lua_State *state, const char *file) {
	printf("reload: %s\n", file);
}


void clearalltimers(void)
{
	if (m_timerinkedRefs.empty())
		return;

	std::map< uv_timer_t*, uint32 >::iterator iter = m_timerinkedRefs.begin();
	for (; iter != m_timerinkedRefs.end(); ++iter)
	{
		uv_timer_stop((*iter).first);
		if ((*iter).first) deallocBytes((*iter).first);
	}

	m_timerinkedRefs.clear();
}

void on_timer_callback(uv_timer_t *handle)
{
	int timerInterrupt_inkedRef = m_timerinkedRefs[handle];
	lua_State* L = get_luastate();

	if (L == NULL ||
		timerInterrupt_inkedRef == LUA_NOREF)
	{
		return;
	}

	lua_rawgeti(L, LUA_REGISTRYINDEX, timerInterrupt_inkedRef);
	int status = lua_pcall(L, 0, 0, 0);

	if (status)
	{
		const char* pErrorMsg = luaL_checkstring(L, -1);
		LOG(ERROR) << "exe_lua_string:" << pErrorMsg;
		SendLog(pErrorMsg, __FILE__, __LINE__,"error");
	}
}

// 得到luastate
lua_State* get_luastate(void)
{
	return g_lua_state;
}

int stopalltimer_tolua(lua_State *L)
{
	clearalltimers();

	return 0;
}

int stoptimer_tolua(lua_State *L)
{
	uint32 timerid = (uint32)luaL_checkinteger(L, 1);

	std::map< uv_timer_t*, uint32 >::iterator iter = m_timerinkedRefs.begin();
	for (;iter != m_timerinkedRefs.end();++iter)
	{
		if ((*iter).second != timerid)
			continue;

		uv_timer_stop((*iter).first);
		m_timerinkedRefs.erase(iter);
		break;
	}

	return 0;
}

int starttimer_tolua(lua_State *L)
{
	uint32 timeout = (uint32)luaL_checkinteger(L, 1);
	uint32 repeat = (uint32)luaL_checkinteger(L, 2);

	uv_timer_t *clientsupdate_timer_req = (uv_timer_t*)allocBytes(sizeof(uv_timer_t));
	uv_timer_init(uv_default_loop(), clientsupdate_timer_req);
	uv_timer_start(clientsupdate_timer_req, on_timer_callback, timeout, repeat);

	luaL_checktype(L, 3, LUA_TFUNCTION);
	lua_pushvalue(L, 3);
	m_timerinkedRefs[clientsupdate_timer_req] = luaL_ref(L, LUA_REGISTRYINDEX);

	lua_pushnumber(L, m_timerinkedRefs[clientsupdate_timer_req]);

	return 1;
}

int setlog_tolua(lua_State* L)
{
	std::string type = luaL_checkstring(L, 1);
	std::string msg =  luaL_checkstring(L, 2);

	if (type == "error")
		LOG(ERROR) << msg;
	else if (type == "info")
		LOG(INFO) << msg;
	else if (type == "waring")
		LOG(WARNING) << msg;
	else if (type == "fatal")
		LOG(FATAL) << msg;

	SendLog(msg.c_str(), __FILE__, __LINE__,type.c_str());

	return 0;
}

const struct luaL_Reg sysLib[] =
{
	{"log", setlog_tolua},
	{"starttimer", starttimer_tolua},
	{"stoptimer", stoptimer_tolua},
	{"stopalltimer", stopalltimer_tolua},
	{"lbreak", c_break},

	{NULL, NULL}       //数组中最后一对必须是{NULL, NULL}，用来表示结束    
};

void reg_sys2Luas(void)
{
	lua_getglobal(g_lua_state, "sys");
	if (lua_isnil(g_lua_state, -1)) {
		lua_pop(g_lua_state, 1);
		lua_newtable(g_lua_state);
	}

	luaL_setfuncs(g_lua_state, sysLib, 0);
	lua_setglobal(g_lua_state, "sys");
}

void lua_init()
{
	g_lua_state = luaL_newstate();
	luaL_openlibs(g_lua_state);
	luaopen_cjson(g_lua_state);

	//lua_register(g_lua_state, "c_break", c_break);

	ldb = ldb_new(g_lua_state, reload);

	LOG(INFO) << "lua init success.";
	SendLog("lua init success.", __FILE__, __LINE__,"info");
}

void lua_exit()
{
	ldb_closesocket();

	if (g_lua_state != NULL)
	{
		ldb_free(ldb);

		lua_close(g_lua_state);
		g_lua_state = NULL;
		LOG(INFO) << "lua close success.";
		SendLog("lua close success.", __FILE__, __LINE__,"info");
	}
}

void reg_all2luas(void)
{
	reg_sys2Luas();
	reg_network2Luas();

	LOG(INFO) << "reg_all2luas success.";
	SendLog("reg_all2luas success.", __FILE__, __LINE__,"info");
}

bool exe_lua_string(const char* luastring, uint32 size)
{
	if (luaL_loadbuffer(g_lua_state, luastring, size, "molnet3") || lua_pcall(g_lua_state, 0, 0, 0))
	{
		// 发生错误时
		const char* pErrorMsg = luaL_checkstring(g_lua_state, -1);
		LOG(ERROR) << "exe_lua_string:" << pErrorMsg;
		SendLog(pErrorMsg, __FILE__, __LINE__,"error");
		return false;
	}

	LOG(INFO) << "lua load success.";
	SendLog("lua load success.", __FILE__, __LINE__,"info");

	return true;
}

/*bool call_table_func(const char * table, const char * func, const char *param)
{
	lua_getglobal(L, table);
	if (lua_istable(L, -1) || lua_type(L, -1) == LUA_TTABLE)
	{
		lua_pushstring(L, func);

		lua_gettable(L, -2);
		lua_pushstring(L, param);
		//lua_pushnil(L);

		if (lua_pcall(L, 1, 0, 0))
		{
			return false;
		}
		return true;
	}
	return false;
}*/

void lua_setup_callback(void)
{
	lua_getglobal(g_lua_state, "main");
	if (lua_istable(g_lua_state, -1) || lua_type(g_lua_state, -1) == LUA_TTABLE)
	{
		//lua_pushstring(g_lua_state, "setup");
		//lua_gettable(g_lua_state, -2);

		lua_getfield(g_lua_state, -1, "setup");

		if (lua_isnil(g_lua_state, -1) || !lua_isfunction(g_lua_state, -1))
		{
			SendLog("lua load 'setup' fail.", __FILE__, __LINE__,"info");
			return;
		}

		int iRet = lua_pcall(g_lua_state, 0, 0, 0);
		if (iRet)
		{
			const char *pErrorMsg = lua_tostring(g_lua_state, -1);
			LOG(ERROR) << "lua_setup_callback:" << pErrorMsg;
			SendLog(pErrorMsg, __FILE__, __LINE__,"error");
		}
	}
}

void lua_network_callback(uint32 socketid, std::string msg)
{
	if (socketid <= 0 || msg.empty())
		return;

	int iRet = 0;

	lua_getglobal(g_lua_state, "main");
	if (lua_istable(g_lua_state, -1) || lua_type(g_lua_state, -1) == LUA_TTABLE)
	{
		//lua_pushstring(g_lua_state, "process_network");
		//lua_gettable(g_lua_state, -2);

		lua_getfield(g_lua_state, -1, "process_network");

		if (lua_isnil(g_lua_state, -1) || !lua_isfunction(g_lua_state,-1))
		{
			SendLog("lua load 'process_network' fail.", __FILE__, __LINE__,"info");
			return;
		}

		lua_pushnil(g_lua_state);
		lua_pushnumber(g_lua_state, socketid);
		lua_pushstring(g_lua_state, msg.c_str());

		iRet = lua_pcall(g_lua_state, 3, 0, 0);

		if (iRet)
		{
			const char *pErrorMsg = lua_tostring(g_lua_state, -1);
			LOG(ERROR) << "lua_network_callback:" << pErrorMsg;
			SendLog(pErrorMsg, __FILE__, __LINE__,"error");
		}
	}
}

// 导入脚本
void lua_loadscript_callback(std::string script)
{
	if (script.empty())
		return;

	int iRet = 0;

	lua_getglobal(g_lua_state, "loadscript");
	lua_pushstring(g_lua_state, script.c_str());
	iRet = lua_pcall(g_lua_state, 1, 0, 0);

	if (iRet)
	{
		const char *pErrorMsg = lua_tostring(g_lua_state, -1);
		LOG(ERROR) << "lua_loadscript_callback:" << pErrorMsg;
		SendLog(pErrorMsg, __FILE__, __LINE__,"error");
	}
	else
	{
		LOG(INFO) << "lua_loadscript_callback successed.";
		SendLog("lua_loadscript_callback successed.", __FILE__, __LINE__,"info");
	}
}

// 从字符串中导入脚本
void lua_loadscriptstring_callback(std::string scriptpath, std::string scriptstring)
{
	if (scriptpath.empty() || scriptstring.empty())
		return;

	int iRet = 0;

	lua_getglobal(g_lua_state, "loadscriptstring");
	lua_pushstring(g_lua_state, scriptpath.c_str());
	lua_pushstring(g_lua_state, scriptstring.c_str());
	iRet = lua_pcall(g_lua_state, 2, 0, 0);

	if (iRet)
	{
		const char *pErrorMsg = lua_tostring(g_lua_state, -1);
		LOG(ERROR) << "lua_loadscript_callback:" << pErrorMsg;
		SendLog(pErrorMsg, __FILE__, __LINE__, "error");
	}
	else
	{
		LOG(INFO) << "lua_loadscript_callback successed.";
		SendLog("lua_loadscript_callback successed.", __FILE__, __LINE__, "info");
	}
}

// 读取指定文件
std::string readfile(std::string filepath)
{
	if (filepath.empty())
		return "";

	char buffer[1024];
	memset(buffer, 0, sizeof(buffer));

	FILE *file = fopen(filepath.c_str(), "r");
	if (file)
	{
		fseek(file, 0, SEEK_END);
		int length = ftell(file);

		fseek(file, 0, SEEK_SET);

		fread(buffer, length,1, file);
		fclose(file);
	}

	return buffer;
}